use tauri::{State, Manager, Emitter};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{info, error, debug};

use crate::devices::scrcpy::ScrcpyClient;
use crate::devices::control::{ControlMsgType, ControlEvent};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TouchEventParams {
    pub device_id: String,
    pub action: u8,
    pub pointer_id: u64,
    pub x: i32,
    pub y: i32,
    pub pressure: f32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyEventParams {
    pub device_id: String,
    pub action: u8,
    pub keycode: u32,
    pub repeat: u32,
    pub metastate: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextInputParams {
    pub device_id: String,
    pub text: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScrollEventParams {
    pub device_id: String,
    pub x: i32,
    pub y: i32,
    pub hscroll: f32,
    pub vscroll: f32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClipboardParams {
    pub device_id: String,
    pub text: String,
    pub paste: bool,
}

pub struct DeviceControlState {
    pub clients: Arc<Mutex<HashMap<String, Arc<ScrcpyClient>>>>,
}

impl DeviceControlState {
    pub fn new() -> Self {
        Self {
            clients: Arc::new(Mutex::new(HashMap::new())),
        }
    }
}

#[tauri::command]
pub async fn start_device_control(
    device_id: String,
    port: u16,
    state: State<'_, DeviceControlState>,
    app: tauri::AppHandle,
) -> Result<(), String> {
    info!("Starting device control for device {}", device_id);

    let mut clients = state.clients.lock().await;
    
    if clients.contains_key(&device_id) {
        return Err(format!("Device {} is already connected", device_id));
    }

    // Create event channels
    let (event_tx, mut event_rx) = tokio::sync::mpsc::channel(100);
    let (reply_tx, mut reply_rx) = tokio::sync::mpsc::channel(100);

    // Create client
    let client = Arc::new(ScrcpyClient::new(
        device_id.clone(),
        port,
        event_tx,
        reply_tx,
    ));

    // Get server path from resources
    let server_path = app.path()
        .resource_dir()
        .map_err(|e| format!("Failed to get resource dir: {}", e))?
        .join("resources")
        .join("scrcpy-server.jar");

    // Connect to device
    client.connect(&server_path).await
        .map_err(|e| format!("Failed to connect to device: {}", e))?;

    // Store client
    clients.insert(device_id.clone(), client.clone());

    // Start event forwarding to frontend
    let app_handle = app.clone();
    tokio::spawn(async move {
        while let Some(reply) = reply_rx.recv().await {
            let _ = app_handle.emit("device-reply", &reply);
        }
    });

    Ok(())
}

#[tauri::command]
pub async fn stop_device_control(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    info!("Stopping device control for device {}", device_id);

    let mut clients = state.clients.lock().await;
    
    if let Some(client) = clients.remove(&device_id) {
        client.disconnect().await
            .map_err(|e| format!("Failed to disconnect: {}", e))?;
        Ok(())
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn send_touch_event(
    params: TouchEventParams,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&params.device_id) {
        // Get screen size for coordinate conversion
        let (width, height) = client.get_screen_size().await
            .map_err(|e| format!("Failed to get screen size: {}", e))?;

        client.control_handler().handle_inject_touch(
            params.action,
            params.pointer_id,
            params.x,
            params.y,
            width as u16,
            height as u16,
            params.pressure,
            0, // action_button
            0, // buttons
        ).await
    } else {
        Err(format!("Device {} is not connected", params.device_id))
    }
}

#[tauri::command]
pub async fn send_key_event(
    params: KeyEventParams,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&params.device_id) {
        client.control_handler().handle_inject_keycode(
            params.action,
            params.keycode,
            params.repeat,
            params.metastate,
        ).await
    } else {
        Err(format!("Device {} is not connected", params.device_id))
    }
}

#[tauri::command]
pub async fn send_text_input(
    params: TextInputParams,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&params.device_id) {
        client.control_handler().handle_inject_text(params.text).await
    } else {
        Err(format!("Device {} is not connected", params.device_id))
    }
}

#[tauri::command]
pub async fn send_scroll_event(
    params: ScrollEventParams,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&params.device_id) {
        let (width, height) = client.get_screen_size().await
            .map_err(|e| format!("Failed to get screen size: {}", e))?;

        client.control_handler().handle_inject_scroll(
            params.x,
            params.y,
            width as u16,
            height as u16,
            params.hscroll,
            params.vscroll,
            0, // buttons
        ).await
    } else {
        Err(format!("Device {} is not connected", params.device_id))
    }
}

#[tauri::command]
pub async fn send_back_button(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_back_or_screen_on(0).await // 0 = ACTION_DOWN
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn rotate_device(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_rotate_device().await
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn set_clipboard(
    params: ClipboardParams,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&params.device_id) {
        let sequence = chrono::Utc::now().timestamp_millis() as u64;
        client.control_handler().handle_set_clipboard(
            sequence,
            params.text,
            params.paste,
        ).await
    } else {
        Err(format!("Device {} is not connected", params.device_id))
    }
}

#[tauri::command]
pub async fn get_clipboard(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_get_clipboard(1).await // 1 = SC_COPY_KEY_COPY
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn expand_notification_panel(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_expand_notification_panel().await
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn expand_settings_panel(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_expand_settings_panel().await
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn collapse_panels(
    device_id: String,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_collapse_panels().await
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}

#[tauri::command]
pub async fn set_screen_power_mode(
    device_id: String,
    mode: u8,
    state: State<'_, DeviceControlState>,
) -> Result<(), String> {
    let clients = state.clients.lock().await;
    
    if let Some(client) = clients.get(&device_id) {
        client.control_handler().handle_set_screen_power_mode(mode).await
    } else {
        Err(format!("Device {} is not connected", device_id))
    }
}